# coding: utf-8
import ipaddress

import servicediscovery
from bytedmysql import sqlalchemy_init
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from apitest.engine.client import Client
from apitest.engine.const.enums import IP
from apitest.engine.const.model import DataBase
from apitest.engine.env import run_env
from apitest.engine.logging import logger


class MySQLClient(Client):

    def __init__(self, db: DataBase):
        super(MySQLClient, self).__init__()

        self.db = db
        self.echo = True
        sqlalchemy_init()
        self.get_db_info()
        engine = create_engine(
            "mysql+pymysql://{}:{}@[{}]:{}/?charset=utf8mb4&&disable_metrics=True".format(self.db.user,
                                                                                          self.db.password,
                                                                                          self.db.host,
                                                                                          str(self.db.port)
                                                                                          )
        )

        self.client = sessionmaker(bind=engine)()
        logger.info("数据库%s已连接。。。" % self.db.name)

    def get_db_info(self):
        # 优先ipv6协议，其次ipv4
        db_lookups = servicediscovery.lookup(self.db.psm, address_family="dual-stack")
        if not db_lookups:
            raise RuntimeError("DB {} not found".format(self.db.psm))
        db = db_lookups[0]
        ipv = ipaddress.ip_address(db.host).version
        if ipv == IP.IPv6.value:
            self.db.host = "[{}]".format(db.host)
        self.db.port = db.port

    def select_one(self, orm_cls, *argv):
        self.client.expire_all()
        self.client.commit()
        return self.client.query(orm_cls).filter(*argv).one()

    def select_all(self, orm_cls, *argv):
        self.client.expire_all()
        self.client.commit()
        return self.client.query(orm_cls).filter(*argv).all()

    def delete_by_po(self, po):
        if not run_env.is_boe():
            raise Exception("Not Boe, writing operation is forbidden!!!")
        self.client.delete(po)
        self.client.commit()

    def delete(self, orm_cls, *argv):
        if not run_env.is_boe():
            raise Exception("Not Boe, writing operation is forbidden!!!")
        res = self.client.query(orm_cls).filter(*argv).all()
        for po in res:
            self.client.delete(po)
        self.client.commit()

    def update_all(self, orm_cls, *clause, **update):
        if not run_env.is_boe():
            raise Exception("Not Boe, writing operation is forbidden!!!")
        self.client.query(orm_cls).filter(*clause).update(update)
        self.client.commit()

    def truncate(self, orm_cls):
        if not run_env.is_boe():
            raise Exception("Not Boe, writing operation is forbidden!!!")
        self.client.execute("truncate table {}".format(orm_cls.__tablename__))

    def insert_by_po(self, po):
        if not run_env.is_boe():
            raise Exception("Not Boe, writing operation is forbidden!!!")
        self.client.add(po)
        self.client.commit()

    def insert(self, orm_cls, *argv):
        if not run_env.is_boe():
            raise Exception("Not Boe, writing operation is forbidden!!!")
        instance = orm_cls()
        for item in argv:
            instance.__setattr__(item.left.description, item.right.value)
        self.insert(instance)

    def close(self):
        self.client.close()
